﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace _1_DBFirst
{  /// <summary>
   /// AES加密解密
   /// 达叔傻乐(darwin.zuo@163.com)
   /// </summary>
    public class AesHelper
    {
        public string Key { set; get; }
        public string IV { set; get; }

        private static string _defaultKey = "JbNp%Rq?Z3`/cS%uk':k}X?p/ ,.3hR9";
        private static string _defaultIV = ")</&fn@C~;aF8DB-";

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="key">32位密钥</param>
        /// <param name="iv">16位向量</param>
        public AesHelper(string key = "", string iv = "")
        {
            Key = FormatKeyIV(key);
            IV = FormatKeyIV(iv, KeyIV.IV);
        }

        private enum KeyIV
        {
            Key,
            IV
        }

        /// <summary>
        /// 对输入的字符串KEY或者IV进行格式化，使之永远是32位或者16位，过长的截短，过短的补长
        /// </summary>
        /// <param name="original"></param>
        /// <param name="keyOrIV"></param>
        /// <returns></returns>
        private string FormatKeyIV(string original = "", KeyIV keyOrIV = KeyIV.Key)
        {
            if (string.IsNullOrWhiteSpace(original)) original = "";

            int targetLength = keyOrIV == KeyIV.Key ? 32 : 16;
            string targetPatten = keyOrIV == KeyIV.Key ? _defaultKey : _defaultIV;
            int originalLength = original.Length;

            string result = "";
            if (originalLength >= targetLength)
            {
                result = original.Substring(0, targetLength);
            }
            else if (originalLength < targetLength)
            {
                result = original + targetPatten.Substring(originalLength);
            }
            return result;
        }


        public string EncryptString(string Value)
        {
            return EncryptString(Value, Key, IV);
        }

        public bool EncryptString(string Value, out string encryptedString)
        {
            return EncryptString(Value, Key, IV, out encryptedString);
        }

        public string DecryptString(string Value)
        {
            string x = DecryptString(Value, Key, IV);
            return x;
        }


        public bool DecryptString(string Value, out string decryptedString)
        {
            bool x = DecryptString(Value, Key, IV, out decryptedString);
            return x;
        }

        #region AES加密解密功能

        /// <summary>
        /// AES加密字符串
        /// </summary>
        /// <param name="Value">需要加密的源字符串</param>
        /// <param name="key">32位密钥</param>
        /// <param name="iv">16位向量</param>
        /// <param name="encryptedString">输出的加密后的字符串，如果加密失败其内容为错误信息</param>
        /// <returns>加密成功返回true否则返回false</returns>
        public static bool EncryptString(string Value, string key, string iv, out string encryptedString)
        {
            if (Value is null) Value = "";

            Rijndael aes = Rijndael.Create();

            try
            {
                byte[] bKey = Encoding.UTF8.GetBytes(key);
                byte[] bIV = Encoding.UTF8.GetBytes(iv);
                byte[] byteArray = Encoding.UTF8.GetBytes(Value);

                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateEncryptor(bKey, bIV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        encryptedString = Convert.ToBase64String(mStream.ToArray());
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                encryptedString = "Error on encryption: " + ex.Message;
                return false;
            }
            finally
            {
                aes.Clear();
            }
        }

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="Value">需要加密的字符串</param>
        /// <param name="key">32位密钥</param>
        /// <param name="iv">16位向量</param>
        /// <returns>返回加密后的字符串，如果失败返回“Error on encryption: ”开头的错误信息</returns>
        public static string EncryptString(string Value, string key, string iv)
        {
            if (Value is null) Value = "";

            Rijndael aes = Rijndael.Create();

            try
            {
                byte[] bKey = Encoding.UTF8.GetBytes(key);
                byte[] bIV = Encoding.UTF8.GetBytes(iv);
                byte[] byteArray = Encoding.UTF8.GetBytes(Value);

                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateEncryptor(bKey, bIV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        string encryptedString = Convert.ToBase64String(mStream.ToArray());
                        return encryptedString;
                    }
                }
            }
            catch (Exception ex)
            {
                string errorMessage = "Error on encryption: " + ex.Message;
                return errorMessage;
            }
            finally
            {
                aes.Clear();
            }
        }

        /// <summary>
        /// AES加密字符串
        /// </summary>
        /// <param name="encryptedString">需要解密的已经加密的字符串</param>
        /// <param name="key">32位密钥</param>
        /// <param name="iv">16位向量</param>
        /// <param name="decryptedString">输出的解密后的字符串，如果解密失败其内容为错误信息</param>
        /// <returns>解密成功返回true否则返回false</returns>
        public static bool DecryptString(string encryptedString, string key, string iv, out string decryptedString)
        {
            if (encryptedString is null) encryptedString = "";

            Rijndael aes = Rijndael.Create();
            try
            {
                byte[] bKey = Encoding.UTF8.GetBytes(key);
                byte[] bIV = Encoding.UTF8.GetBytes(iv);
                byte[] byteArray = Convert.FromBase64String(encryptedString);

                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(bKey, bIV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        decryptedString = Encoding.UTF8.GetString(mStream.ToArray());
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                decryptedString = "Error on decryption: " + ex.Message;
                return false;
            }
            finally
            {
                aes.Clear();
            }
        }


        /// <summary>
        /// AES解密字符串
        /// </summary>
        /// <param name="encryptedString">需要解密的加密后的字符串</param>
        /// <param name="key">32位密钥</param>
        /// <param name="iv">16位向量</param>
        /// <returns>返回解密后的字符串，如果失败返回“Error on decryption: ”开头的错误信息</returns>
        public static string DecryptString(string encryptedString, string key, string iv)
        {
            if (encryptedString is null) encryptedString = "";

            Rijndael aes = Rijndael.Create();
            try
            {
                byte[] bKey = Encoding.UTF8.GetBytes(key);
                byte[] bIV = Encoding.UTF8.GetBytes(iv);
                byte[] byteArray = Convert.FromBase64String(encryptedString);

                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(bKey, bIV), CryptoStreamMode.Write))
                    {
                        cStream.Write(byteArray, 0, byteArray.Length);
                        cStream.FlushFinalBlock();
                        string decryptedString = Encoding.UTF8.GetString(mStream.ToArray());
                        return decryptedString;
                    }
                }
            }
            catch (Exception ex)
            {
                string errorMessage = "Error on decryption: " + ex.Message;
                return errorMessage;
            }
            finally
            {
                aes.Clear();
            }
        }
        #endregion AES加密解密功能

    }
}
